﻿using Shinva.Variables.Models;
using Shinva.Variables.Type.combination;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 复杂数据类型基类
/// </summary>
namespace Shinva.Variables.Interface
{
    public class PlcComplexBase : IPlcMember
    {

        #region IMember，IPlcMember实现通用属性
        //变量名称
        public string Name { get; set; } = "PlcComplexBase";
        //变量全名
        public string FullName { get; set; }
        //变量符号
        public string Symbol { get; set; }
        //数据类型
        public DataType DataType { get; set; }
        //变量地址偏移量
        public PlcAddress Address { get; set; } = new PlcAddress(0,0);
        //占用位数
        public int SizeInBits { get; set; }

        //上一级变量
        public IPlcMember Parent { get; set; }

        /// <summary>
        /// 根据占用位数计算占用字节数
        /// </summary>
        /// <returns></returns>
        public int SizeInBytes() => (SizeInBits + 7) / 8;
        #endregion


        #region 自定义复杂数据类型属性
        //成员类型
        private readonly List<IPlcMember> _members = new List<IPlcMember>();

        // 添加获取成员列表的方法
        public List<IPlcMember> GetMembers() => _members;

       
        private int _currentByteOffset { get;  set; }  // 当前分配到的字节位置
        public string Value { get ; set ; }

        /// <summary>
        /// 添加成员到成员列表
        /// </summary>
        /// <param name="member"></param>
        public void AddMember(IPlcMember member)
        {
            member.Parent = this;
            member.Address = new PlcAddress(_currentByteOffset, 0);
            _currentByteOffset += member.SizeInBytes();
            _members.Add(member);
            UpdateSize(member);
        }
        /// <summary>
        /// 结构体中添加一个子元素就要调用此方法更新这个结构体的大小
        /// </summary>
        private void UpdateSize(IPlcMember member)
        {
            SizeInBits = getBitSize();
        }
        private int getBitSize()
        {
            int res = 0;
            for (int i = 0; i < _members.Count; i++)
            {
                if (_members[i] is PlcStruct pst)
                {
                    res += pst.getBitSize();
                }
                else
                {
                    res += _members[i].SizeInBits;
                }
            }
            return res;
        }
        #endregion

        /// <summary>
        /// 公用方法，调整地址偏移量
        /// </summary>
        /// <param name="byteOffset"></param>
        public void compileAddr(int byteOffset = 0)
        {

            // int _bitOffset = 0;
            int _byteOffset = byteOffset;
            for (int i = 0; i < _members.Count; i++)
            {
                //结构体类型的处理
                if (_members[i] is PlcStruct pst)
                {
                    pst.Address = new PlcAddress(_byteOffset);
                    pst.compileAddr(_byteOffset);
                    //var test = _members[i].Name;
                    //var test2 = _byteOffset;
                    _byteOffset += pst.SizeInBytes();
                }
                //数组类型的处理
                else if (_members[i] is PlcArray pa)
                {
                    pa.Address = new PlcAddress(_byteOffset);
                    pa.compileAddr(_byteOffset);
                    _byteOffset += pa.SizeInBytes();
                }
                else
                {
                    var test = _members[i];
                    _members[i].Address = new PlcAddress(_byteOffset);
                    _byteOffset += _members[i].SizeInBytes();
                }
            }
        }
    }
}
